package org.atf.mgr;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.atf.model.dao.AtfSchedulerDAO;
import org.atf.model.dao.AuditDAO;
import org.atf.model.entity.Audit;
import org.atf.model.entity.Jobs;
import org.atf.model.entity.User;
import org.atf.services.SchedulerJob;
import org.atf.utils.ATFUtils;
import org.atf.utils.SchedulerJobsXmlDAO;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.ee.servlet.QuartzInitializerServlet;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.CalendarIntervalScheduleBuilder.*;
import static org.quartz.JobKey.*;

public class SchedulerManager {
	AtfSchedulerDAO atfSchedulerDAO = new AtfSchedulerDAO();
	AuditDAO auditDAO = new AuditDAO();
	Scheduler sched =null;
	private static Logger logger = Logger.getLogger(SchedulerManager.class);
	
	public SchedulerManager(){
		init();
	}
	public void init(){
		logger.debug("initialiting the schedule Manager");
		WebContext ctx = WebContextFactory.get();
		logger.debug("ctx: "+ctx);
		ServletContext sctx=ctx.getServletContext();
		logger.debug("sctx: "+sctx);
		StdSchedulerFactory factory =  (StdSchedulerFactory)sctx.getAttribute(QuartzInitializerServlet.QUARTZ_FACTORY_KEY);
		try {
			logger.debug("factory: "+factory);
			sched = factory.getScheduler("ATFScheduler");
			logger.debug("Scheduler: "+sched.toString());
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public String getSessionUsername(){
			
			WebContext ctx = WebContextFactory.get();
			HttpSession session=ctx.getSession();
			User user =(User) session.getAttribute("ATFUser");
			if( user != null){
				return user.getUsername();
			}else{
				return "";
			}
		}
	public String addToScheduler(Integer scheduleId){
		logger.debug("scheduleId: "+scheduleId);
		Jobs job=atfSchedulerDAO.getJobsId(scheduleId);
		if(sched == null){
			return "ERROR: Scheduler Service is not Found";
		}
		if( job == null){	
			return "ERROR: Unable to find Job Details";
		}
		logger.debug("jobDetails: "+job.toString());
		if( job.getStatus() != null){
			if(job.getStatus().equalsIgnoreCase("scheduled")){
				return "WARN: This Job is already scheduled";
			}
		}
		if(checkSchedulerJob(job.getName())){
			return "WARN: Jobs is already scheduled";
		}
		logger.debug("Scheduling job: "+job.getJobId());
			JobDetail job1 = newJob(SchedulerJob.class)
					.withIdentity(String.valueOf(job.getJobId()), "group1")
					.usingJobData("jobId", job.getJobId())
					.build();
			Trigger  trigger= null;
			Date startDate=job.getStartTime();
			//use to persistence the jobs to jobs.xml
			HashMap<String,String> jobDetails=new HashMap<String,String>();
		    HashMap<String,String> jobMapDetails=new HashMap<String,String>();
		    HashMap<String,String> jobTrigger=new HashMap<String,String>();
		    
		    //job
		    jobDetails.put("name", job.getName());
		    jobDetails.put("group", "group1");
		    jobDetails.put("description", job.getDescription());
		    jobDetails.put("job-class", "org.atf.services.SchedulerJob");
		    //job data
		    jobMapDetails.put("jobId", String.valueOf(job.getJobId()));
		    
		    //trigger
		    jobTrigger.put("name", job.getName());
		    jobTrigger.put("group", "group1");
		    jobTrigger.put("job-name", job.getName());
		    jobTrigger.put("job-group", "group1");
		    
	
			Calendar sCal=Calendar.getInstance();
			SimpleDateFormat formatter = new SimpleDateFormat(SchedulerJobsXmlDAO.JOB_XML_DATE_FORMAT);
		    if(job.getStartTime() !=null){
		    	sCal.setTime(job.getStartTime());
		     }
		    jobTrigger.put("start-time", formatter.format(sCal.getTime()));
		    if(job.getEndTime() != null ){
		    	jobTrigger.put("end-time", formatter.format(job.getEndTime()));
		    }
		    jobTrigger.put("repeat-interval", String.valueOf(job.getInterval()));
		    if( job.getRepetitions().equalsIgnoreCase("Min")){
		    	trigger = newTrigger()
					    .withIdentity(job.getName(), "group1")
					    .startAt(sCal.getTime())
					    .endAt(job.getEndTime())
					    .withSchedule(calendarIntervalSchedule().withIntervalInMinutes(job.getInterval()))
					    .build();
				jobTrigger.put("repeat-interval-unit","MINUTE");
		    }else if(job.getRepetitions().equalsIgnoreCase("Hour")){
		    	trigger = newTrigger()
					    .withIdentity(job.getName(), "group1")
					    .startAt(sCal.getTime())
					    .endAt(job.getEndTime())
					    .withSchedule(calendarIntervalSchedule().withIntervalInHours(job.getInterval()))
					    .build();
				jobTrigger.put("repeat-interval-unit","HOUR");
		    }else if(job.getRepetitions().equalsIgnoreCase("Day")){
		    	trigger = newTrigger()
					    .withIdentity(job.getName(), "group1")
					    .startAt(sCal.getTime())
					    .endAt(job.getEndTime())
					    .withSchedule(calendarIntervalSchedule().withIntervalInDays(job.getInterval()))
					    .build();
				jobTrigger.put("repeat-interval-unit","DAY");
		    }else if(job.getRepetitions().equalsIgnoreCase("Week")){
		    	trigger = newTrigger()
					    .withIdentity(job.getName(), "group1")
					    .startAt(sCal.getTime())
					    .endAt(job.getEndTime())
					    .withSchedule(calendarIntervalSchedule().withIntervalInWeeks(job.getInterval()))
					    .build();
				jobTrigger.put("repeat-interval-unit","WEEK");
		    }else if(job.getRepetitions().equalsIgnoreCase("Month")){
		    	trigger = newTrigger()
					    .withIdentity(job.getName(), "group1")
					    .startAt(sCal.getTime())
					    .endAt(job.getEndTime())
					    .withSchedule(calendarIntervalSchedule().withIntervalInMonths(job.getInterval()))
					    .build();
				jobTrigger.put("repeat-interval-unit","MONTH");
		    }else{
			   trigger = newTrigger()
					   .withIdentity(job.getName(), "group1")
					   .startAt(sCal.getTime())
					   .build();
				   }
		    String result="";
		    if(trigger != null){
		    	try {
		    		logger.debug("Scheduling the job: "+job.getName());
		    		if(jobTrigger.containsKey("repeat-interval-unit")){
		    			logger.debug("Scheduling the job Later: "+job.getJobId());
		    			auditDAO.insertAudit(new Audit(org.atf.utils.ATFUtils.getSessionUsername(),job.getJobId(),
		    					"SCHEDULEJOB",sCal.getTime(), job.getEndTime(),"Schedule a Job: "+job.getName()));
		    			result=SchedulerJobsXmlDAO.addSchedulerToJobFile(jobDetails,jobMapDetails,jobTrigger);
		    			if(result.equalsIgnoreCase("OK")){
		    				logger.debug("Updating the Status the job: "+job.getName()+ "scheduled: scheduled");
		    				atfSchedulerDAO.updateScheduleStatus(scheduleId, "scheduled");
		    			}
		    		}else{
		    			Date date=sched.scheduleJob(job1, trigger);
		    			logger.debug("Scheduling the job now: "+job.getJobId());
		    			auditDAO.insertAudit(new Audit(org.atf.utils.ATFUtils.getSessionUsername(),job.getJobId(),
		    					"SCHEDULEJOB",sCal.getTime(), job.getEndTime(),"Schedule a Job to Run Now: "+job.getName()));
		    			if(date != null){
		    				logger.debug("Updating the Status the job: "+job.getName()+ "scheduled: scheduled");
		    				atfSchedulerDAO.updateScheduleStatus(scheduleId, "scheduled");
		    				result="OK: Scheduled for Now";
		    			}
		    			
		    		}
		    	}catch (SchedulerException e) {
					// TODO Auto-generated catch block
					
					logger.error(e);
				}
		    }
		   return result;
	}
	
	public List<HashMap<String,String>> getSchedulerList(){
		List<HashMap<String,String>> jobList= new ArrayList<HashMap<String,String>>();
		SimpleDateFormat formatter = new SimpleDateFormat("d EEE MMM yyyy h:mm:ss a");
			 
		     try {
		    	 for (String groupName : sched.getJobGroupNames()) {
					for (JobKey jobKey : sched.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
					  String jobName = jobKey.getName();
					  String jobGroup = jobKey.getGroup();
					  HashMap<String, String> temp=new HashMap<String,String>();
					  //get job's trigger
					//  List<Trigger> triggers = (List<Trigger>) sched.getTriggersOfJob(jobKey);
					 // Date nextFireTime = triggers.get(0).getNextFireTime(); 
	 
						logger.debug("[jobName] : " + jobName + " [groupName] : "
							+ jobGroup + " - " );
						if(!jobGroup.equalsIgnoreCase("JobSchedulingDataLoaderPlugin")){
							temp.put("jobName", jobName);
							temp.put("jobGroup", jobGroup);
							List<Trigger> triggers = (List<Trigger>) sched.getTriggersOfJob(jobKey);
							Date nextFireTime = triggers.get(0).getNextFireTime(); 
							Date startTime = triggers.get(0).getStartTime();
							Date prevFireTime = triggers.get(0).getPreviousFireTime();
							if(startTime != null){
								temp.put("startTime", formatter.format(startTime));
							}else{
								temp.put("startTime", "");
							}
							if(nextFireTime != null){
								temp.put("nextRun", formatter.format(nextFireTime));
							}else{
								temp.put("nextRun", "");
							}
							if(prevFireTime != null){
								temp.put("lastRun", formatter.format(prevFireTime));
							}else{
								temp.put("lastRun", "");
							}
							
							jobList.add(temp);
						}
						
					  }
		    	 }
			} catch (SchedulerException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		 
		return jobList;
	}
	
	public boolean checkSchedulerJob(String jobName){
		logger.debug("jobName: "+jobName);
		try {
			boolean runtimejob=sched.checkExists(jobKey(jobName, "group1"));
			boolean inFileExists=SchedulerJobsXmlDAO.checkExists(jobName);
			if( runtimejob || inFileExists){
				return true;
			}
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return false;
	}
	public String removeSchedulerJob(Integer jobId){
		
		logger.debug("jobId: "+jobId);
		Jobs job=atfSchedulerDAO.getJobsId(jobId);
		
		String result="WARN: UNknown Error Occured";
		if(job != null){
			if(sched != null){
				try {
						if(sched.deleteJob(jobKey(job.getName(), "group1"))){
							SchedulerJobsXmlDAO.removeSchedulerFromJobFile(job.getName());	
						}	
						if(atfSchedulerDAO.updateScheduleStatus(job.getJobId(), "")){
							//atfSchedulerDAO.updateJobNextRun(job.getJobId(), null);
							result="Schedule Removed";
							auditDAO.insertAudit(new Audit(org.atf.utils.ATFUtils.getSessionUsername(),job.getJobId(),
			    					"UNSCHEDULEDJOB",Calendar.getInstance().getTime(), Calendar.getInstance().getTime(),"Removed a Job: "+job.getName()));
						}
				} catch (SchedulerException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else{
				result="ERROR: Scheduler is not found";
			}
		}else{
			result="WARN: Scheduled id not defined";
		}
		return result;
	}
	
	
	
	
}
